/*
* @(#)GregorianCalendar.java 1.29 98/02/02
*
* (C) Copyright Taligent, Inc. 1996-1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996-1997 - All Rights Reserved
*
* Portions copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
*
* The original version of this source code and documentation is copyrighted
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
* materials are provided under terms of a License Agreement between Taligent
* and Sun. This technology is protected by multiple US and International
* patents. This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies. Please refer to the file "copyright.html"
* for further important copyright and licensing information.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*
*/
package java.util;
/**
* GregorianCalendar
is a concrete subclass of
* Calendar
* and provides the standard calendar used by most of the world.
*
*
* The standard (Gregorian) calendar has 2 eras, BC and AD. * *
* This implementation handles a single discontinuity, which corresponds * by default to the date the Gregorian calendar was instituted (October 15, * 1582 in some countries, later in others). This cutover date may be changed * by the caller. * *
* Prior to the institution of the Gregorian calendar, New Year's Day was * March 25. To avoid confusion, this calendar always uses January 1. A manual * adjustment may be made if desired for dates that are prior to the Gregorian * changeover and which fall between January 1 and March 24. * *
* Example: *
** * @see Calendar * @see TimeZone * @version 1.29 02/02/98 * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu */ public class GregorianCalendar extends Calendar { // Internal notes: // This algorithm is based on the one presented on pp. 10-12 of // "Numerical Recipes in C", William H. Press, et. al., Cambridge // University Press 1988, ISBN 0-521-35465-X. /** * Useful constant for GregorianCalendar. */ public static final int BC = 0; /** * Useful constant for GregorianCalendar. */ public static final int AD = 1; // Note that the Julian date used here is not a true Julian date, since // it is measured from midnight, not noon. private static final long julianDayOffset = 2440588; private static final int millisPerDay = 24 * 60 * 60 * 1000; private static final int NUM_DAYS[] = {0,31,59,90,120,151,181,212,243,273,304,334}; // 0-based, for day-in-year private static final int LEAP_NUM_DAYS[] = {0,31,60,91,121,152,182,213,244,274,305,335}; // 0-based, for day-in-year private static final int MONTH_LENGTH[] = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based private static final int LEAP_MONTH_LENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based // This is measured from the standard epoch, not in Julian Days. // Default is 00:00:00 local time, October 15, 1582. private long gregorianCutover = -12219292800000L; // The onset of the Julian calendar is 45 B.C. The Julian day // number for the start of the year 45 B.C. is 1712653. We compute // the Julian onset as epoch-based millis. Note that this number is // useful for rough comparison purposes only; it's not exact. [LIU] private static long JULIAN_ONSET = (1712653 - julianDayOffset) * millisPerDay; // Useful millisecond constants private static final long ONE_SECOND = 1000; private static final long ONE_MINUTE = 60*ONE_SECOND; private static final long ONE_HOUR = 60*ONE_MINUTE; private static final long ONE_DAY = 24*ONE_HOUR; private static final long ONE_WEEK = 7*ONE_DAY; // Proclaim serialization compatiblity with JDK 1.1 static final long serialVersionUID = -8125100834729963327L; /** * Converts time as milliseconds to Julian date. * @param millis the given milliseconds. * @return the Julian date number. */ private static final long millisToJulianDay(long millis) { if (millis >= 0) return julianDayOffset + (millis / millisPerDay); else return julianDayOffset + ((millis - millisPerDay + 1) / millisPerDay); } /** * Converts Julian date to time as milliseconds. * @param julian the given Julian date number. * @return time as milliseconds. */ private static final long julianDayToMillis(long julian) { return (julian - julianDayOffset) * millisPerDay; } /** * Constructs a default GregorianCalendar using the current time * in the default time zone with the default locale. */ public GregorianCalendar() { this(TimeZone.getDefault(), Locale.getDefault()); } /** * Constructs a GregorianCalendar based on the current time * in the given time zone with the default locale. * @param zone the given time zone. */ public GregorianCalendar(TimeZone zone) { this(zone, Locale.getDefault()); } /** * Constructs a GregorianCalendar based on the current time * in the default time zone with the given locale. * @param aLocale the given locale. */ public GregorianCalendar(Locale aLocale) { this(TimeZone.getDefault(), aLocale); } /** * Constructs a GregorianCalendar based on the current time * in the given time zone with the given locale. * @param zone the given time zone. * @param aLocale the given locale. */ public GregorianCalendar(TimeZone zone, Locale aLocale) { super(zone, aLocale); setTimeInMillis(System.currentTimeMillis()); } /** * Constructs a GregorianCalendar with the given date set * in the default time zone with the default locale. * @param year the value used to set the YEAR time field in the calendar. * @param month the value used to set the MONTH time field in the calendar. * Month value is 0-based. e.g., 0 for January. * @param date the value used to set the DATE time field in the calendar. */ public GregorianCalendar(int year, int month, int date) { super(TimeZone.getDefault(), Locale.getDefault()); this.set(ERA, AD); this.set(YEAR, year); this.set(MONTH, month); this.set(DATE, date); } /** * Constructs a GregorianCalendar with the given date * and time set for the default time zone with the default locale. * @param year the value used to set the YEAR time field in the calendar. * @param month the value used to set the MONTH time field in the calendar. * Month value is 0-based. e.g., 0 for January. * @param date the value used to set the DATE time field in the calendar. * @param hour the value used to set the HOUR_OF_DAY time field * in the calendar. * @param minute the value used to set the MINUTE time field * in the calendar. */ public GregorianCalendar(int year, int month, int date, int hour, int minute) { super(TimeZone.getDefault(), Locale.getDefault()); this.set(ERA, AD); this.set(YEAR, year); this.set(MONTH, month); this.set(DATE, date); this.set(HOUR_OF_DAY, hour); this.set(MINUTE, minute); } /** * Constructs a GregorianCalendar with the given date * and time set for the default time zone with the default locale. * @param year the value used to set the YEAR time field in the calendar. * @param month the value used to set the MONTH time field in the calendar. * Month value is 0-based. e.g., 0 for January. * @param date the value used to set the DATE time field in the calendar. * @param hour the value used to set the HOUR_OF_DAY time field * in the calendar. * @param minute the value used to set the MINUTE time field * in the calendar. * @param second the value used to set the SECOND time field * in the calendar. */ public GregorianCalendar(int year, int month, int date, int hour, int minute, int second) { super(TimeZone.getDefault(), Locale.getDefault()); this.set(ERA, AD); this.set(YEAR, year); this.set(MONTH, month); this.set(DATE, date); this.set(HOUR_OF_DAY, hour); this.set(MINUTE, minute); this.set(SECOND, second); } /** * Compares this calendar to the specified object. * The result is* // get the supported ids for GMT-08:00 (Pacific Standard Time) * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000); * // if no ids were returned, something is wrong. get out. * if (ids.length == 0) * System.exit(0); * * // begin output * System.out.println("Current Time"); * * // create a Pacific Standard Time time zone * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]); * * // set up rules for daylight savings time * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000); * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000); * * // create a GregorianCalendar with the Pacific Daylight time zone * // and the current date and time * Calendar calendar = new GregorianCalendar(pdt); * Date trialTime = new Date(); * calendar.setTime(trialTime); * * // print out a bunch of interesting things * System.out.println("ERA: " + calendar.get(Calendar.ERA)); * System.out.println("YEAR: " + calendar.get(Calendar.YEAR)); * System.out.println("MONTH: " + calendar.get(Calendar.MONTH)); * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR)); * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH)); * System.out.println("DATE: " + calendar.get(Calendar.DATE)); * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH)); * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR)); * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK)); * System.out.println("DAY_OF_WEEK_IN_MONTH: " * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH)); * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM)); * System.out.println("HOUR: " + calendar.get(Calendar.HOUR)); * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY)); * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE)); * System.out.println("SECOND: " + calendar.get(Calendar.SECOND)); * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND)); * System.out.println("ZONE_OFFSET: " * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); * System.out.println("DST_OFFSET: " * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); * System.out.println("Current Time, with hour reset to 3"); * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override * calendar.set(Calendar.HOUR, 3); * System.out.println("ERA: " + calendar.get(Calendar.ERA)); * System.out.println("YEAR: " + calendar.get(Calendar.YEAR)); * System.out.println("MONTH: " + calendar.get(Calendar.MONTH)); * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR)); * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH)); * System.out.println("DATE: " + calendar.get(Calendar.DATE)); * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH)); * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR)); * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK)); * System.out.println("DAY_OF_WEEK_IN_MONTH: " * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH)); * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM)); * System.out.println("HOUR: " + calendar.get(Calendar.HOUR)); * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY)); * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE)); * System.out.println("SECOND: " + calendar.get(Calendar.SECOND)); * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND)); * System.out.println("ZONE_OFFSET: " * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours * System.out.println("DST_OFFSET: " * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours **
true
if and only if the argument is
* not null
and is a Calendar
object that
* represents the same calendar as this object.
* @param obj the object to compare with.
* @return true
if the objects are the same;
* false
otherwise.
*/
public boolean equals(Object obj) {
// This body moves to Calendar in 1.2
if (this == obj)
return true;
if (!(obj instanceof Calendar))
return false;
Calendar that = (Calendar)obj;
return getTimeInMillis() == that.getTimeInMillis() &&
isLenient() == that.isLenient() &&
getFirstDayOfWeek() == that.getFirstDayOfWeek() &&
getMinimalDaysInFirstWeek() == that.getMinimalDaysInFirstWeek() &&
getTimeZone().equals(that.getTimeZone());
}
/**
* Compares the time field records.
* Equivalent to comparing result of conversion to UTC.
* @param when the Calendar to be compared with this Calendar.
* @return true if the current time of this Calendar is before
* the time of Calendar when; false otherwise.
*/
public boolean before(Object when) {
// This body moves to Calendar in 1.2
return when instanceof Calendar &&
getTimeInMillis() < ((Calendar) when).getTimeInMillis();
}
/**
* Compares the time field records.
* Equivalent to comparing result of conversion to UTC.
* @param when the Calendar to be compared with this Calendar.
* @return true if the current time of this Calendar is after
* the time of Calendar when; false otherwise.
*/
public boolean after(Object when) {
// This body moves to Calendar in 1.2
return when instanceof Calendar &&
getTimeInMillis() > ((Calendar) when).getTimeInMillis();
}
/**
* Sets the GregorianCalendar change date. This is the point when the
* switch from Julian dates to Gregorian dates occurred. Default is
* 00:00:00 local time, October 15, 1582. Previous to this time and date
* will be Julian dates.
*
* @param date the given Gregorian cutover date.
*/
public void setGregorianChange(Date date)
{
gregorianCutover = date.getTime();
}
/**
* Gets the Gregorian Calendar change date. This is the point when the
* switch from Julian dates to Gregorian dates occurred. Default is
* 00:00:00 local time, October 15, 1582. Previous to
* this time and date will be Julian dates.
* @return the Gregorian cutover time for this calendar.
*/
public final Date getGregorianChange()
{
return new Date(gregorianCutover);
}
private static final int julianDayToDayOfWeek(long julian)
{
// If julian is negative, then julian%7 will be negative, so we adjust
// accordingly. We add 1 because Julian day 0 is Monday.
int dayOfWeek = (int)((julian + 1) % 7);
return dayOfWeek + ((dayOfWeek < 0) ? (7 + SUNDAY) : SUNDAY);
}
/**
* Convert the time as milliseconds to the "big" fields. Millis must be
* given as local wall millis to get the correct local day. For example,
* if it is 11:30 pm Standard, and DST is in effect, the correct DST millis
* must be passed in to get the right date.
*
* Fields that are completed by this method: ERA, YEAR, MONTH, DATE,
* DAY_OF_WEEK, DAY_OF_YEAR, WEEK_OF_YEAR, WEEK_OF_MONTH,
* DAY_OF_WEEK_IN_MONTH.
*/
private final void timeToFields(long theTime)
{
int year, month, date, dayOfWeek, dayOfYear, weekCount, era = AD;
//---------------------------------------------------------------------
// BEGIN modified caldat()
//---------------------------------------------------------------------
// The following variable names are somewhat cryptic. Unfortunately,
// they are from the original program cited above, and no explanation
// for their meaning is given. Given that the algorithm is cryptic too,
// perhaps it doesn't matter...
long ja, jb, jd;
long jc, je; // changed from int to fix number overflow problem.
long julian = millisToJulianDay(theTime);
if (theTime >= gregorianCutover)
{
long jalpha = (long) (((double) (julian - 1867216) - 0.25)
/ 36524.25);
ja = julian + 1 + jalpha - (long) (0.25 * jalpha);
}
else
{
ja = julian;
}
jb = ja + 1524;
jc = (long) Math.floor(6680.0 + ((double) (jb - 2439870) - 122.1) / 365.25);
jd = (long) Math.floor(365*jc + (0.25 * jc));
je = (long) ((jb-jd)/30.6001);
date = (int) (jb-jd-(long) (30.6001 * je));
month = (int) je - 1;
if (month > 12)
month -= 12;
year = (int) (jc-4715);
if (month > 2)
--year;
if (year <= 0)
{
era = BC;
year = 1-year;
}
//---------------------------------------------------------------------
// END modified caldat()
//---------------------------------------------------------------------
internalSet(ERA, era);
internalSet(YEAR, year);
internalSet(MONTH, month-1); // 0-based
internalSet(DATE, date);
dayOfWeek = julianDayToDayOfWeek(julian);
internalSet(DAY_OF_WEEK, dayOfWeek); // CLH, 8-7-96
if (isLeapYear(year))
dayOfYear = LEAP_NUM_DAYS[month-1] + date; // month: 0-based
else
dayOfYear = NUM_DAYS[month-1] + date; // month: 0-based
internalSet(DAY_OF_YEAR, dayOfYear);
internalSet(WEEK_OF_YEAR, weekNumber(dayOfYear, dayOfWeek));
internalSet(WEEK_OF_MONTH, weekNumber(date, dayOfWeek));
internalSet(DAY_OF_WEEK_IN_MONTH, (date-1) / 7 + 1);
}
/**
* Return the week number of a day, within a period. This may be the week number in
* a year, or the week number in a month. Usually this will be a value >= 1, but if
* some initial days of the period are excluded from week 1, because
* minimalDaysInFirstWeek is > 1, then the week number will be zero for those
* initial days. Requires the day of week for the given date in order to determine
* the day of week of the first day of the period.
*
* @param dayOfPeriod Day-of-year or day-of-month. Should be 1 for first day of period.
* @param day Day-of-week for given dayOfPeriod. 1-based with 1=Sunday.
* @return Week number, one-based, or zero if the day falls in part of the
* month before the first week, when there are days before the first
* week because the minimum days in the first week is more than one.
*/
private int weekNumber(int dayOfPeriod, int dayOfWeek)
{
// Determine the day of the week of the first day of the period
// in question (either a year or a month). Zero represents the
// first day of the week on this calendar.
int periodStartDayOfWeek = (dayOfWeek - getFirstDayOfWeek() - dayOfPeriod + 1) % 7;
if (periodStartDayOfWeek < 0) periodStartDayOfWeek += 7;
// Compute the week number. Initially, ignore the first week, which
// may be fractional (or may not be). We add periodStartDayOfWeek in
// order to fill out the first week, if it is fractional.
int weekNo = (dayOfPeriod + periodStartDayOfWeek - 1)/7;
// If the first week is long enough, then count it. If
// the minimal days in the first week is one, or if the period start
// is zero, we always increment weekNo.
if ((7 - periodStartDayOfWeek) >= getMinimalDaysInFirstWeek()) ++weekNo;
return weekNo;
}
/**
* Determines if the given year is a leap year. Returns true if the
* given year is a leap year.
* @param year the given year.
* @return true if the given year is a leap year; false otherwise.
*/
public boolean isLeapYear(int year)
{
// Compute the rough millis for the year. We only need this number to be
// good enough to compare it against JULIAN_ONSET.
long equivalent_millis = (long)((year - 1970) * 365.2422 * millisPerDay);
// No leap years before onset of Julian calendar
if (equivalent_millis < JULIAN_ONSET)
return false;
return (equivalent_millis > gregorianCutover) ?
((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))) : // Gregorian
(year%4 == 0); // Julian
}
/**
* Overrides Calendar
* Converts UTC as milliseconds to time field values.
* The time is not
* recomputed first; to recompute the time, then the fields, call the
* complete
method.
* @see Calendar#complete
*/
protected void computeFields()
{
int gmtOffset = getTimeZone().getRawOffset();
long localMillis = time + gmtOffset;
// Time to fields takes the wall millis (Standard or DST).
timeToFields(localMillis);
int era = internalGet(ERA);
int year = internalGet(YEAR);
int month = internalGet(MONTH);
int date = internalGet(DATE);
int dayOfWeek = internalGet(DAY_OF_WEEK);
long days = (long) (localMillis / millisPerDay);
int millisInDay = (int) (localMillis - (days * millisPerDay));
if (millisInDay < 0) millisInDay += millisPerDay;
// Call getOffset() to get the TimeZone offset. The millisInDay value must
// be standard local millis.
int dstOffset = getTimeZone().getOffset(era,year,month,date,dayOfWeek,millisInDay) -
gmtOffset;
// Adjust our millisInDay for DST, if necessary.
millisInDay += dstOffset;
// If DST has pushed us into the next day, we must call timeToFields() again.
// This happens in DST between 12:00 am and 1:00 am every day. The call to
// timeToFields() will give the wrong day, since the Standard time is in the
// previous day.
if (millisInDay >= millisPerDay)
{
millisInDay -= millisPerDay;
localMillis += dstOffset;
timeToFields(localMillis);
}
// Fill in all time-related fields based on millisInDay. Call internalSet()
// so as not to perturb flags.
internalSet(MILLISECOND, millisInDay % 1000);
millisInDay /= 1000;
internalSet(SECOND, millisInDay % 60);
millisInDay /= 60;
internalSet(MINUTE, millisInDay % 60);
millisInDay /= 60;
internalSet(HOUR_OF_DAY, millisInDay);
internalSet(AM_PM, millisInDay / 12);
internalSet(HOUR, millisInDay % 12);
internalSet(ZONE_OFFSET, gmtOffset);
internalSet(DST_OFFSET, dstOffset);
// Careful here: We are manually setting the time stamps[] flags to
// INTERNALLY_SET, so we must be sure that the above code actually does
// set all these fields.
for (int i=0; i* Field names Minimum Greatest Minimum Least Maximum Maximum * ----------- ------- ---------------- ------------- ------- * ERA 0 0 1 1 * YEAR 1 1 5,000,000 5,000,000 * MONTH 0 0 11 11 * WEEK_OF_YEAR 0 0 53 54 * WEEK_OF_MONTH 0 0 4 6 * DAY_OF_MONTH 1 1 28 31 * DAY_OF_YEAR 1 1 365 366 * DAY_OF_WEEK 1 1 7 7 * DAY_OF_WEEK_IN_MONTH -1 -1 4 6 * AM_PM 0 0 1 1 * HOUR 0 0 11 12 * HOUR_OF_DAY 0 0 23 23 * MINUTE 0 0 59 59 * SECOND 0 0 59 59 * MILLISECOND 0 0 999 999 * ZONE_OFFSET -12*60*60*1000 -12*60*60*1000 12*60*60*1000 12*60*60*1000 * DST_OFFSET 0 0 1*60*60*1000 1*60*60*1000 **/ private static final int MinValues[] = {0,1,0,0,0,1,1,1,-1,0,0,0,0,0,0,-12*60*60*1000,0}; private static final int GreatestMinValues[] = {0,1,0,0,0,1,1,1,-1,0,0,0,0,0,0,-12*60*60*1000,0};// same as MinValues private static final int LeastMaxValues[] = {1,5000000,11,53,4,28,365,7,4,1,11,23,59,59,999, 12*60*60*1000,1*60*60*1000}; private static final int MaxValues[] = {1,5000000,11,54,6,31,366,7,6,1,12,23,59,59,999, 12*60*60*1000,1*60*60*1000}; /** * Returns minimum value for the given field. * e.g. for Gregorian DAY_OF_MONTH, 1 * Please see Calendar.getMinimum for descriptions on parameters and * the return value. */ public int getMinimum(int field) { return MinValues[field]; } /** * Returns maximum value for the given field. * e.g. for Gregorian DAY_OF_MONTH, 31 * Please see Calendar.getMaximum for descriptions on parameters and * the return value. */ public int getMaximum(int field) { return MaxValues[field]; } /** * Returns highest minimum value for the given field if varies. * Otherwise same as getMinimum(). For Gregorian, no difference. * Please see Calendar.getGreatestMinimum for descriptions on parameters * and the return value. */ public int getGreatestMinimum(int field) { return GreatestMinValues[field]; } /** * Returns lowest maximum value for the given field if varies. * Otherwise same as getMaximum(). For Gregorian DAY_OF_MONTH, 28 * Please see Calendar.getLeastMaximum for descriptions on parameters and * the return value. */ public int getLeastMaximum(int field) { return LeastMaxValues[field]; } }